# -*- coding: utf-8 -*-

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
# 参数说明：
# image_array: 原灰度图像矩阵
# kernel: 卷积核
# 返回值：原图像与算子进行卷积后的结果
def ImgConvolve(image_array, kernel):
    image_arr = image_array
    img_dim1,img_dim2 = image_arr.shape
    # img_dim1 x img_dim2 的图片
    print("img_dim1={},img_dim2={}".format(img_dim1,img_dim2)) 
    k_dim1,k_dim2 = kernel.shape
    # k_dim1 x k_dim2 的卷积核
    print("k_dim1={},k_dim2={}".format(k_dim1,k_dim2)) 
    AddW = int((k_dim1 - 1)/2)
    AddH = int((k_dim2 - 1)/2)
    print("AddW={},AddH={}".format(AddW,AddH))     
    # padding 填充
    temp = np.zeros([img_dim1 + AddW * 2,
                     img_dim2 + AddH * 2])
    print("temp.shape=",temp.shape)
    # 将原图拷贝到临时图片的中央
    temp[AddW: AddW + img_dim1, 
         AddH: AddH + img_dim2] = image_arr[:,:]
    # 初始化一张同样大小的图片作为输出图片
    output = np.zeros_like(a = temp)
    print("output.shape=",output.shape)
    # 将扩充后的图和卷积核进行卷积
    for i in range(AddW, AddW + img_dim1):# i = [1,121]
        for j in range(AddH, AddH + img_dim2):# j = [1,121]
            output[i][j] = int(np.sum(temp[i-AddW:i+AddW+1,
                            j-AddW:j+AddW+1]*kernel))
    return output[AddW:AddW+img_dim1,
                  AddH:AddH+img_dim2]
    

# 提取竖直方向特征    
kernel_1 = np.array(
        [[-1,0,1],
        [-2,0,2],
        [-1,0,1]])
    
# 提取水平方向特征    
kernel_2 = np.array(
        [[-1,-2,-1],
        [0,0,0],
        [1,2,1]])

# Laplace 扩展算子
# 拉普拉斯变换
kernel_3 = np.array(
        [[1,1,1],
        [1,-8,1],
        [1,1,1]])

# 打开图像并转化成灰度图像
image = Image.open("cat.jpg").convert("L")

# 将图像转化成数组
image_array = np.array(image)

# 卷积操作
sobel_x = ImgConvolve(image_array, kernel_1)
sobel_y = ImgConvolve(image_array, kernel_2)
laplace = ImgConvolve(image_array, kernel_3)

# 显示图像
plt.imshow(image_array, cmap = 'gray')
plt.axis("off")
plt.show()

plt.imshow(sobel_x, cmap = 'gray')
plt.axis("off")
plt.show()

plt.imshow(sobel_y, cmap = 'gray')
plt.axis("off")
plt.show()

plt.imshow(laplace, cmap = 'gray')
plt.axis("off")
plt.show()
